//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "DMD_Main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
 : TForm(Owner)
{
}


//------------------------------//
// Decompress the ROM data      //
//------------------------------//
int  __fastcall TForm1::Decomp( LONG lpStart, LONG lpSize )
{
  LONG comp_posi,
       tree_posi,
       lpEnd;

  FILE *f1,
       *f2;

  BYTE *tree,
       *comp = &ram[0x1000];

  // No entry unless active
  if ( !rom || !ram ){
    ShowMessage( "Error: Must load a ROM file first." );
    return -1;
  }
  // Make the file name
//  mkdir( AnsiString( AnsiString( cur_dir ) + "\\dump" ).c_str( ) );
  //
  sprintf( fil2, "%s\\%08X.dmp", dirc, lpStart);
  sprintf( fil3, "%s\\%08X.txt", dirc, lpStart );

  // Open the file(s)
  f1 = fopen( fil2, "wb" );
  f2 = fopen( fil3, "wt" );
  //
  if ( !f1 || !f2 )
  { //
  	 fcloseall( );
    ShowMessage( "Error: Could not open WORKING file(s)." );
	   return -1;
  }// END IF

  // Try to get memory for the tree
  lpSize <<= 1;
  tree = (BYTE *)malloc( lpSize );
  if ( !tree )
  {
    ShowMessage( "Fatal Error: Out of needed memory!" );
    Close( );
    return -1;
  }

  // Load up the data for the tree
  memset( tree, 0, lpSize );
  memcpy( tree, &rom[ lpStart - lpSize ], lpSize );
  // Get to the Static data
  comp_posi = 0;
  tree_posi = 0;

  // Loop through the routine
  lpEnd    = lpStart;
  while ( tree_posi < lpSize )
  { // Load up testing BYTE
    ram[0x00] = tree[ tree_posi++ ];
    ram[0x02] = 0;
    //
    while( ram[0x02] < 8 )
    { // Test for a bit set
      // If so, then it's static data
      if ( ram[0x00] & 0x80 )
        comp[ comp_posi++ ] = rom[ lpStart++ ];
      // We have compression
      else
        comp[ comp_posi++ ] = 0;
      //
      // Increment the counter
      ram[0x02]++;
      ram[0x00] <<= 1;
    }// WEND
  }// WEND

  // Store the data to the file
  fprintf( f2, ".COMP %s %s %08lX %08lX %04X\n", fil1, fil2, lpEnd, lpStart, (lpSize >> 1) );
  fwrite( comp, 1, comp_posi, f1 );
  fcloseall( );
  //
  _free( tree );
  ShowMessage( "Data decompressed to the file" );

  return 0;
}// END OF SUB


//------------------------------//
//                              //
//------------------------------//
int  __fastcall TForm1::Recomp( LONG lpStart, LONG lpEnd, LONG lpSize )
{
  FILE *f1 = NULL,
       *f2 = NULL;
  LONG comp_posi,
       data_posi,
       tree_posi;
  BYTE *tree,
       *romp = &ram[0x01000],
       *comp = &ram[0x10000];

  BYTE data;

  //
  if ( !rom || !ram ){
    ShowMessage( "Error: Must load a ROM file first." );
    return -1;
  }

  // Open the file(s)
  f2 = fopen( fil2, "rb" );
  if ( !f2 )
  {
    fcloseall( );
    ShowMessage( "Error: Could not open WORKING file(s)..." );
    return -1;
  }// END IF

  fread( comp, 1, FileSize( f2 ), f2 );

  // Try to get memory for the tree
  lpSize <<= 1;
  tree = (BYTE *) malloc( lpSize );
  if ( !tree ) return -1;

  // Load up the data for the tree
  memset( tree, 0, lpSize );
//  memcpy( tree, &rom[ lpStart ], lpSize );
  // Get to the Static data
  comp_posi = 0;
  tree_posi = 0;
  data_posi = 0;

  // Loop through the routine
  while ( tree_posi < lpSize )
	 { //
    ram[0x00] = 0;
    ram[0x04] = 0;
    //
    while( ram[0x00] < 8 )
    { // Loop thru and check the data
      ram[0x02] = comp[ comp_posi++ ];
      //
      if ( !ram[0x02] )
        ram[ 0x04] <<= 1;
      else
      {
        ram[ 0x04] <<= 1;
        ram[ 0x04]  |= 1;
        romp[ data_posi++ ] = ram[0x02];
      }
  	   // Increment the counter
      if ( data_posi == 0x289 )
        data_posi = data_posi;
	     ram[0x00]++;
  	 }// WEND
    //
    tree[ tree_posi++ ] = ram[0x04];
  }// WEND

  // Store the data to the file
  if ( (data_posi + lpStart) <= lpEnd )
  {
    memcpy( &rom[ lpStart - lpSize ], tree, lpSize );
    memcpy( &rom[ lpStart ], romp, data_posi );
  }
  else
    ShowMessage( "Compressed size is too large" );
  //
  fclose( f2 );
  _free( tree );

  return 0;
}


//------------------------------//
//                              //
//------------------------------//
LONG  __fastcall TForm1::FileSize( FILE *tf )
{
  LONG value;

  // Test file
  if ( !tf ) return -1;

  // Get size
  fseek( tf, 0, SEEK_END );
  value = ftell( tf );
  fseek( tf, 0, SEEK_SET );

  return value;
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::RecompresswCOMPfile1Click(TObject *Sender)
{
  FILE *tf;
  char buf[256];

  FOpen->Title      = "Open COMP data file";
  FOpen->Filter     = "TEXT File | *.txt";
  FOpen->InitialDir = cur_dir;

  //---------------------//
  //                     //
  //---------------------//
  if ( FOpen->Execute( ) )
  { //
    tf = fopen( FOpen->FileName.c_str( ), "rt" );
    if ( !tf )
    {
      ShowMessage( "Error: Could not opne COMP file." );
      return;
    }

    //---------------------//
    //                     //
    //---------------------//
    while( fgets( buf, 256, tf ) )
    {
      if ( !strncmpi( buf, ".comp", 5 ) )
      {
        sscanf( buf, "%s %s %s %lX %lX %X", &fil1, &fil1, &fil2, &lpStart, &lpEnd, &lpSize );
        Recomp( lpStart, lpEnd, lpSize );
      }
    }

    //
    ShowMessage( "Process completed without known errors" );
  }
  //
  fclose( tf );
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
  _free( rom );
  _free( ram );
  fcloseall( );
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::N647CDClick(TObject *Sender)
{
  TMenuItem *m = (TMenuItem *)Sender;
  char buf[256],
      file[MAXPATH];

  sscanf( m->Caption.c_str( ), "%s", &buf );
  //
  Decomp( strtoul( &buf[1], NULL, 16 ), m->Tag );
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  getcwd( cur_dir, MAXPATH );
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::SaveROMfile1Click(TObject *Sender)
{
  FILE *tf;

  tf = fopen( fil1, "wb" );
  if ( !tf )
  {
    ShowMessage( "Error: Could not open ROM file." );
    return;
  }
  //
  fwrite( rom, 1, ROMSize, tf );
  fclose( tf );
  ShowMessage( "ROM file saved." );
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::OpenROMfile1Click(TObject *Sender)
{
  FILE *tf;

  FOpen->Title      = "Open ROM File";
  FOpen->Filter     = "NES ROM | *.nes";
  FOpen->InitialDir = cur_dir;
  //
  if ( FOpen->Execute( ) )
  { // Create Dump directory!
    getcwd( dirc, MAXPATH );
    strcat( dirc, "\\Dumps" );
    mkdir( dirc );

    //
    strcpy( fil1, FOpen->FileName.c_str( ) );
    tf = fopen( fil1, "rb" );
    if ( !tf ){
      ShowMessage("Fatal Error: Could not open file!");
      return;
    }
    //
    _free( rom );
    _free( ram );
    //
    rom = (BYTE *)malloc( ROMSize = FileSize( tf ) );
    ram = (BYTE *)malloc( 0x20000 );
    //
    if ( !rom || !ram )
    { //
      fclose( tf );
      ShowMessage( "Fatal Error: Could not allocate needed memory!" );
      Close( );
    }

    // Read in the data
    fread( rom, 1, ROMSize, tf );
    fclose( tf );
    //---------------------------------//
    // Make sure it's the correct ROM  //
    // Usually ROM's Header Name       //
    //---------------------------------//
    if ( strncmp( &rom[0x07FFF5], "DOBULE MOON", 11 ) )
    { //
      ShowMessage("Error: This is not the ROM used.\n"
                  "Please load the correct ROM."
                 );
      _free( rom );
      return;
    }
  }
}

